package cn.lingyangwl.framework.knife4j.micro.reactive;

import cn.lingyangwl.framework.tool.core.StringUtils;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.*;

/**
 * Swagger资源配置
 * 在网关上添加Swagger资源配置，用于聚合其他微服务中Swagger的api-docs访问路径；
 *
 * @author shenguangyang
 */
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
    private static final Logger log = LoggerFactory.getLogger(SwaggerResourceConfig.class);
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;
    private final PcKnife4jProperties knife4JExtProperties;

    public static final String API_URI = "v3/api-docs";

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        // 获取所有路由的ID
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        //过滤出配置文件中定义的路由->过滤出Path Route Predicate->根据路径拼接成api-docs路径->生成SwaggerResource
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
            route.getPredicates().stream()
                    .filter(predicateDefinition -> {
                        Map<String, String> args = predicateDefinition.getArgs();
                        Set<Map.Entry<String, String>> entries = args.entrySet();
                        for (Map.Entry<String, String> entry : entries) {
                            String value = entry.getValue();
                            List<String> excludeUris = knife4JExtProperties.getExcludeUri();
                            for (String excludeUri : excludeUris) {
                                if (StringUtils.matches(excludeUri, Collections.singletonList(value))) {
                                    return false;
                                }
                            }
                        }
                        return ("Path").equalsIgnoreCase(predicateDefinition.getName());
                    })
                    .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
                            predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                    .replace("**", API_URI))));
        });

        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        log.info("name: {}, location: {}", name, location);
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
}